Loading Indicators

Loading indicators offer visual cues regarding ongoing processes.

They come in two main types: determinate and indeterminate.

In addition to these, Skeleton Screens and In-Component Loaders offer unique forms of feedback that do not fit neatly into the determinate or indeterminate categories:

Determinate Loaders

50%
32%
32%

Indeterminate Loaders

Indeterminate-loader-circle Placeholder text...
Indeterminate-loader-line Alternative option depending on context of use

In-component Loaders

In-component loaders offer localised feedback within specific UI elements, such as buttons or form fields, to inform users that an action is being processed.

Use in-component loaders sparingly; not all actions require them.

Reserve their use for tasks that take additional time or processing to ensure users stay informed without disrupting their workflow.


In Buttons:


In Fields:

Skeleton Screens

Skeleton Screen Example




CSS Properties

                

/*Determinate Loading Indicators*/

    /*Base*/

        .progress-container {
            display: flex;
            flex-direction: column;
            align-items: flex-start;
            width: 100%;
        }
        .progress-label-container {
            display: flex;
            justify-content: space-between;
            align-items: center;
            width: 100%;
        }
        progress {
            height: 15px;
            width: 100%;
            appearance: none;
        }
        .determinate-linear-small {
            height: 7px; 
            width: 100%;
            appearance: none;
        }
        .progress-label {
            font-size: 14px;
            font-family: var(--base-font-family);
            text-align: left;
        }
        .progress-count {
            font-size: 14px;
            font-family: var(--base-font-family);
            font-weight: 600;
            color: var(--MidBlue);
            text-align: right;
            margin-left: auto;
        }

    /* Style*/
        progress::-webkit-progress-bar {
            background-color: var(--Grey-xxl);
            border-radius: 10px;
            border: none;
        }
        progress::-webkit-progress-value {
            background-color: var(--PuertoRico);
            border-radius: 10px;
        }
        .determinate-linear::-webkit-progress-bar {
            background-color: var(--Grey-xxl);
        }
        .determinate-linear::-webkit-progress-value {
            background-color: var(--PuertoRico);
        }
        .determinate-linear-small::-webkit-progress-bar {
            background-color: var(--Grey-xxl);
        }
        .determinate-linear-small::-webkit-progress-value {
            background-color: var(--PuertoRico);
        }

    /*Doughnut*/

        /* Pie */
            #doughnut {
                width: 100px;
                height: 100px;
                border-radius: 50%;
                background: conic-gradient(var(--PuertoRico) 0deg 180deg,var(--Grey-xxl) 180deg 360deg);
                position: relative;
            }

        /* Inner circle */
            #inner_circle {
                width: 75px;
                height: 75px;
                border-radius: 50%;
                background: var(--White);
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                display: flex;
                align-items: center;
                justify-content: center;
            }
            .progress-count-doughnut {
                font-size: 18px;
                font-family: var(--base-font-family);
                font-weight: 500;
                color: var(--Black);
                text-align: center;
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
            }

/*Indeterminate Loaders*/

    .loader-container-il { 
        width: 150px; 
        height: 100px; 
        font-family: var(--base-font-family);
        text-align: center; 
        color: black;
        background-color: white;
        border-radius: 10px;
        border: none;
        box-shadow: 0px 3px 6px rgba(0,0,0, 0.15);
        margin: 10px;
        padding: 20px 10px 20px 10px;
        display: flex;
        flex-direction: column; 
        align-items: center; 
        justify-content: space-between;
        overflow: hidden;
    }

/*In-component Loaders*/

        /*Button loading States*/

        .btn-primary.loading,
        .btn-primary.loader-active {
            background-color: var(--PuertoRico-xd);
            border-color: var(--PuertoRico-xd); 
            color: white;
          }

        .btn-secondary.loading,
        .btn-secondary.loader-active {
          background-color: var(--PuertoRico-d);
          border-color: var(--PuertoRico-d); 
          color: white;
        }

        .btn-tertiary.loading,
        .btn-tertiary.loader-active {
            background-color: var(--PuertoRico);
            border-color: var(--PuertoRico); 
            color: white;
          }

        .btn-primary-small.loading,
        .btn-primary-small.loader-active {
            background-color: var(--PuertoRico-xd);
            border-color: var(--PuertoRico-xd); 
            color: white;
        }

        .btn-secondary-small.loading,
        .btn-secondary-small.loader-active {
            background-color: var(--PuertoRico-d);
            border-color: var(--PuertoRico-d); 
            color: white;
            }

        .btn-tertiary-small.loading,
        .btn-tertiary-small.loader-active {
            background-color: var(--PuertoRico);
            border-color: var(--PuertoRico); 
            color: white;
        }

        /* Button loader */
   
            .loader {
                display: none;
                border: 4px solid rgb(255, 255, 255, 0.5);
                border-top: 4px solid white;
                border-radius: 50%;
                width: 14px;
                height: 14px;
                animation: spin 1s linear infinite;
                padding: 0px; 
                margin-right: 7px;
            }

        /* Style for the loader to make it centered in the small buttons */

            .btn-primary-small .loader {
                position: absolute;
                margin-right: 0px;
            }

            .btn-secondary-small .loader {
                position: absolute;
                margin-right: 0px;
            }

            .btn-tertiary-small .loader {
                position: absolute;
                margin-right: 0px;
            }

        /* Loader-active state (shared) */

            button.loader-active {
                cursor: wait; 
            }

        /* Show loader on loading */

            .loader-active .loader {
            display: block; 
            }

        /* Spinner animation */
            @keyframes spin {
                0% {
                    transform: rotate(0deg);
                }
                100% {
                    transform: rotate(360deg);
                }
            }

        /* Hide icon when loader is visible */
            #icon {
                display: block;
            }

        /* Show the loader and hide the icon */
            .loader-active #icon {
                display: none;
            }
            .loader-active #loader {
                display: block;
            }

                
            

Javascript

                

// Select the specific buttons by their IDs
    const buttonIds = ["iconloader", "iconloader1", "iconloader2", "iconloader3", "iconloader4", "iconloader5", "iconloader6", "iconloader7", "iconloader8", "iconloader9"];

    // Loop through each ID and apply loader behavior to the corresponding button
    buttonIds.forEach((id) => {
        const button = document.getElementById(id);
        const loader = button.querySelector(".loader");
        const icon = button.querySelector(".material-symbols-rounded");

        button.addEventListener("click", function () {
            // Add the loader-active class
            button.classList.add("loader-active");

            // Ensure the icon and loader visibility updates properly
            if (icon) icon.style.display = "none";
            if (loader) loader.style.display = "block";

            // Simulate loading and revert after 3 seconds
            setTimeout(function () {
                button.classList.remove("loader-active");
                if (icon) icon.style.display = "block";
                if (loader) loader.style.display = "none";
            }, 3000); // Adjust the duration as needed
        });
    });

    // Select all buttons with class 'btn-base-small'
    const buttons = document.querySelectorAll(".btn-base-small");

    buttons.forEach(button => {
        const loader = button.querySelector(".loader");
        const icon = button.querySelector(".material-symbols-rounded");

        button.addEventListener("click", function () {
            // Add the loader-active class
            button.classList.add("loader-active");

            // Hide the icon and show the loader
            if (icon) icon.style.display = "none";
            if (loader) loader.style.display = "block";

            // Simulate loading and revert after 3 seconds
            setTimeout(function () {
                button.classList.remove("loader-active");
                if (icon) icon.style.display = "block";
                if (loader) loader.style.display = "none";
            }, 3000); // Adjust the duration as needed
        });
    });